#!/usr/bin/env python
# -*- coding:UTF-8 -*-
# Copyright (c) 2007 ismail ata kurt
version = "0.1"
cr="""
+======================================================+
|               _________    ______ ______             | 
|  _____  ____________  /_______  /____  /____         |
|  __  / / /  _ \  __  /_  _ \_  //_/_  /_  _ \        |
|  _  /_/ //  __/ /_/ / /  __/  ,<  _  / /  __/        |
|  _\__, / \___/\__,_/  \___//_/|_| /_/  \___/         |
|  /____/                                              |
|                                                      |
|   Yedekle  v0.1                                      |
+======================================================+
"""
import os,sys
import locale,gettext

#-------------------------------------------#
#Config

cpanel_users_dir ="/var/cpanel/users"
backup_dir ="yedekler"
mysql_host ="localhost"
backupdir_log="/etc/yedekle/logs"
#Keep backups for x days
backup_rotate_interval=7

#--------------------------------------------#

i18n = lambda x:x;

#lang =gettext.translation('yedekle')
#i18n = lang.gettext

def color_print(string,color_code):
	return "\033[%dm%s\033[0m"%(color_code,string)
	

#Error
error = color_print(i18n("Error:"),31)

try :
	import MySQLdb
except ImportError:
	
	print error + i18n(" In order to use yedekle ,MySQLdb required")

from time import time,gmtime,strftime
from re import compile,split,search,sub
from commands import getoutput




verbose_mode=0


today = gmtime(time())
year = today[0]
month = today[1]
day = today[2]

def main():
    global backup_mode,verbose_mode,backup_rotate_interval
    
    
    backup_mode	=   0	
    flush_mode  =   0
    stat_mode   =   0
    rotate_mode =   0
    help_mode   =   0
    
    #check user
    if not os.geteuid()==0:
   	 sys.exit(error+i18n(" Only root can run this script\n"))
    
    #arg check
    for arg in sys.argv[1:]:
        if (arg=="--verbose" or arg=="-v"):
            verbose_mode = 1
            #[Verbose mode activated]
            print "[Verbose mode]\n"

    for arg in sys.argv:        
        if (arg=="--backup" or arg=="-b"):
	    backup_mode=1
	elif (arg=="--stat" or arg=="-s"):
            stat_mode = 1
            show_stats(backupdir_log)
        elif(arg=="--flush" or arg=="-f"):
            flush_mode = 1
            flush()
        elif(arg=="--rotate" or arg=="-r"):
            rotate_mode = 1
            rotate_backups()
        elif(arg=="--help" or arg=="-h"):
            help_mode = 1
            show_help()
        
    if(stat_mode==1 or flush_mode==1 or rotate_mode==1 or help_mode==1):
        return 0
    
    
    
    if(verbose_mode==1):print i18n("Starting backup...\n")
    
    if(not backup_mode==1):
	    show_help()
	    sys.exit()
    
    if(not os.path.exists(backupdir_log)):
	    getoutput("mkdir -p %s"%backupdir_log)
    
    rotate_backups()

    #Kullanıcı listesini al
    #Get user list
    users = cpanel_accounts()
    
    for u in users:
        backup_account(u)
    
    
    if(verbose_mode==1):print color_print(i18n("Back up process completed\n"),32)
    
def show_help():
	print cr
	#shows this help and exits
	print "-h ,  --help	"+i18n("Show this help an exits")
	#backup
	print "-b ,  --backup	"+i18n("Backup")
	#deletes all backups
	print "-f ,  --flush	"+i18n("Deletes all backups")
	#deletes backups older then %s days
	print "-r ,  --rotate	"+i18n("Deletes backups older than %s day(s)") % backup_rotate_interval
	#shows backup statistics
	print "-s ,  --stat	"+i18n("Shows backup statistics\n")
	
	
	
def backup_account(account_name):
    try:
    	#Backuping account %s 
    	if(verbose_mode==1):print i18n("Backuping account %s \n") % color_print(account_name,36)
    
    	if(not os.path.exists("/home/%s"%account_name)):
		if(verbose_mode==1):print (error+i18n(" There is no such account (terminated account)"))
		return
	    
    	user_backupdir = "/home/%s/%s"%(account_name,backup_dir)
    	user_backupdir_year = "%s/%s"%(user_backupdir,year)
    	user_backupdir_month = "%s/%s"%(user_backupdir_year,month)
    	user_backupdir_dump= "%s/%s"%(user_backupdir_month,"dumps")
    
    
    	if not os.path.exists(user_backupdir):
        	os.mkdir(user_backupdir)

    	if not os.path.exists(user_backupdir_year):
        	os.mkdir(user_backupdir_year)

    	if not os.path.exists(user_backupdir_month):
        	os.mkdir(user_backupdir_month)

    	if not os.path.exists(user_backupdir_dump):
        	os.mkdir(user_backupdir_dump)

    	if not os.path.exists(backupdir_log):
        	os.mkdir(backupdir_log) 
    
    	#Mysql Dump oluştur
    	#Create Mysql dump
    	user_databases = getUser_databases(account_name)
    	for dbs in user_databases:
        	dumpMysqlDatabase(dbs[0],user_backupdir_dump+"/"+dbs[0]+".sql")
    
    	db_dumps = dumped_databases(user_backupdir_dump)
    
    	#Dosyaları yedekle
    	#Backup Files
    
    	if os.path.exists("/home/"+account_name+"/"+"public_html"): 
        	if(verbose_mode==1):print i18n("Backuping folder %s"%" /home/"+account_name+"/"+"public_html/")
	  
        	tgz = user_backupdir_month+"/"+ str(day )+ "_" + str(month) + "_" + str(year) + "_" + account_name + ".tgz "
		compress_files_dir=" /home/"+account_name+"/"+"public_html/"
		cmd= "tar -czf " +tgz + compress_files_dir+ " " + db_dumps
        	getoutput(cmd)
        	
	
		#izinleri ayarla
		#Set permissions
		cmd = "chmod -R 0600 "+user_backupdir
		getoutput(cmd)
	
		#Grubu ve sahibi ayarla
		#set owner & group
		cmd = "chown -R "+account_name+"."+account_name+" "+user_backupdir
		getoutput(cmd)
	
        	if(os.path.isfile(user_backupdir_month+"/"+ str(day )+ "_" + str(month) + "_" + str(year) + "_" + account_name + ".tgz")):
            		now = strftime("%H:%M:%S") 
            		file_size = os.stat(user_backupdir_month+"/"+ str(day )+ "_" + str(month) + "_" + str(year) + "_" + account_name + ".tgz")[6]
            		file = open(backupdir_log + "/" + str(day)+ "_" + str(month) +"_" + str(year) +"_yedek.log","a")
            		file.write('%d  %s  %s\n'%(file_size,account_name,now))
            		file.close 
    
    	#Geçici mysql dump dosyalarını sil
    	#Delete temporary dump files
    	for dbs in user_databases:
        	os.unlink(user_backupdir_dump+"/"+dbs[0]+".sql")
    
    except OSError:	
	sys.exit(error+i18n(' OS error\n'))
    except IOError:
	sys.exit(error+i18n(" Disc error\n"))
    except KeyboardInterrupt:
	sys.exit(i18n("Keyboard Interrupt , Control-C"))
    except:
	sys.exit(error+i18n(" Unexpected error"))

def show_stats(folder):
    from glob import glob
    
    glb=glob(folder+'/*.log')
    pattern = compile("  ")
    rmv_pattern = compile("\n")
    date_pattern1 = compile("(.*)_yedek")
    date_pattern2 = compile("(.*)/")
    _pattern = compile("_")
           
	   
    if(len(glb)==0):
        
        print i18n("No backup to describe")
        return 0

    total_size=0
        
    for log_file in glb:
        if search(date_pattern1,log_file):
            
            file = open(log_file,"r")
            x = split(date_pattern1,log_file)
            x= sub(date_pattern2,"",x[1])
            x = sub(_pattern,"/",x)
            
            
            print i18n("%s dated backups")%color_print(x,36)
        
            size_list=[]
            user_list=[]
            tmp_size = 0
            for sts in file:
                sts = sub(rmv_pattern,"",sts)            
                tmp=split(pattern,sts)
                total_size+=long(tmp[0])
                tmp_size+=long(tmp[0])
                size_list.append(long(tmp[0]))
                user_list.append(tmp[1])
        
            list2d=[size_list,user_list]
            list2d=matrixsort2d(list2d,0)
	    
            for i in range(len(list2d[0])):
                print "%s   %s"%(smart_size(list2d[0][i]),list2d[1][i])
                
            
            file.close
            print i18n("Backup size : %s\n")%smart_size(tmp_size)
    print i18n("Total backup size : %s")%smart_size(long(total_size)) 



def dumped_databases(folder):
    dbs = os.listdir(folder)
    rslt = ""
    for d in dbs:
        rslt += folder+"/"+ d+" "
    
    return rslt

def dumpMysqlDatabase(database_name,output):
    #Backing up %s datebase
    if(verbose_mode==1):print i18n("Backuping database %s")%color_print(database_name,35)
    getoutput("mysqldump --add-drop-table --host=%s -uroot -p%s %s >%s" % (mysql_host,get_mysql_root(),database_name,output))
    
def getUser_databases(account_name):
    
    
    if(verbose_mode==1):print i18n("Searching  %s's databases...\n")%color_print(account_name,36)
    
    db = MySQLdb.Connect(mysql_host,"root",get_mysql_root(),"mysql")
    cursor = db.cursor()
    cursor.execute("show databases like '"+account_name+"_%'")
    result = cursor.fetchall()
    del(db,cursor)
    
    return result

def rotate_backups():
    from datetime import datetime, timedelta
    
    from glob import glob
    
    now = datetime(year, month, day)
    pattern = compile("log/(.*)")
    pattern2 = compile("  ")
    pattern3 = compile("_")
    
    exclude_list=[]
      
    for i in range(0,abs(backup_rotate_interval)):
        diff=timedelta(days=-i)+now
        m=lambda x:int(x)
        exclude_list.append(str(m(diff.strftime("%d")))+"_"+ str(m(diff.strftime("%m"))) +"_" +diff.strftime("%Y")+"_yedek.log")
    
    logs=glob(backup_dir+'/log/*.log')
    log_list=[]
    if(len(logs)>0):
        for i in range(len(logs)):
            if(search(pattern,logs[i])):
                log_list.append(search(pattern,logs[i]).group(1))
    
    del(logs)

    for i in log_list:
        for s in exclude_list:
            if(i==s):
                log_list.remove(s)
    
    
    del(exclude_list)
    
    if(len(log_list)>0):
        #Deleting old backups
        if(verbose_mode==1):print i18n("Deleting old backups...")
        for i in log_list:
            file = open(backupdir_log+"/"+i,"r")
            for s in file:
               tmp = split(pattern2,s)
               backup_date = split(pattern3,i)
               backup="%s/%s/%s/%s/%s_%s_%s_%s.tgz"%(backup_dir,tmp[1],backup_date[2],backup_date[1],backup_date[0],backup_date[1],backup_date[2],tmp[1])
               if(os.path.isfile(backup)):
                    os.unlink(backup)
            file.close
        
        if(verbose_mode==1):print i18n("Old backups deleted")
    else:
        
        if(verbose_mode==1):print i18n("No old backup to delete")
    
def flush():
    from shutil import rmtree
    from glob import glob 
    
    i=0
    users =cpanel_accounts()
    
    for u in users:
	user_backup_dir="/home/%s/%s"%(u,backup_dir)
	
    	if(os.path.exists(user_backup_dir)):
        	i+=1
		rmtree(user_backup_dir)
        	
        	
        	if(verbose_mode==1):print i18n("%s's backup(s) succesfuly deleted"%color_print(u,36))
    glb = glob(backupdir_log+"/*.log")
    
    for log_file in glb:
	os.unlink(log_file)
    
    if(verbose_mode==1):
	    if(i==0): print i18n("No backup to flush")
    
def get_mysql_root():
    pattern=compile("--user=root --pass=(\S+)")
    mysqladmin=getoutput("mysqladmin --print-defaults")
    s1=search(pattern,mysqladmin)
    
    if(s1):
        return s1.group(1) 
    else:
        
        sys.exit(error+i18n(" Can't find Mysql root password"))
    
def cpanel_accounts():
    users=[]
    
    try:
    	users = os.listdir(cpanel_users_dir)
    except OSError:	
	sys.exit(error+i18n('Cpanel is not installed or there is no cpanel account'))
    except IOError:
	sys.exit(error+i18n(" Disc error\n"))
    except KeyboardInterrupt:
	sys.exit(i18n("Keyboard Interrupt , Control-C"))
    except:
	sys.exit(error+i18n(" Unexpected error"))
    
    return users;



def matrixsort2d(list2d,SortByColumn):
    x= len(list2d[SortByColumn])
    other_row =abs(SortByColumn-1)
    for i in range(x):
        for s in range(x):
            if(list2d[SortByColumn][s]>list2d[SortByColumn][i]):
                tmp = list2d[SortByColumn][i]
                list2d[SortByColumn][i]=list2d[SortByColumn][s]
                list2d[SortByColumn][s] = tmp
                tmp = list2d[other_row][i]
                list2d[other_row][i]=list2d[other_row][s]
                list2d[other_row][s] = tmp
                
                
    
    return list2d

def smart_size(bytes):
    sizein_kb = bytes/1024.0
    sizein_mb = sizein_kb/1024.0
    sizein_gb = sizein_mb/1024.0
    ssize=0
    if(sizein_kb>=1):
        ssize = color_print(str(round(sizein_kb,2)),32) + " kb"
    if(sizein_mb>=1):
        ssize = color_print(str(round(sizein_mb,2)),35) + " mb"
    if(sizein_gb>=1):
        ssize = color_print(str(round(sizein_gb,2)),31) + " gb"
    
    return ssize

main()
 
